探索 React ReactDOM 强大的 DOM 渲染工具。了解 ReactDOM.render、hydrate、unmountComponentAtNode 和 findDOMNode,以构建动态用户界面。
React ReactDOM:DOM 渲染工具综合指南
React 是一个用于构建用户界面的强大 JavaScript 库。其核心在于,React 将对文档对象模型 (DOM) 的直接操作抽象出来,让开发者可以专注于描述他们期望的 UI 状态。然而,React 本身需要一种方式与浏览器的 DOM 交互,才能将这些 UI 描述变为现实。这就是 ReactDOM 发挥作用的地方。这个包提供了将 React 组件渲染到 DOM 中并管理其交互的特定方法。
理解 ReactDOM 的角色
ReactDOM 充当了 React 基于组件的世界与浏览器 DOM 之间的桥梁。它提供了将 React 组件渲染到特定 DOM 节点、在数据变化时更新它们、甚至在不再需要时移除它们的功能。可以把它看作是在浏览器中驱动 React 应用程序视觉呈现的引擎。
区分 React 和 ReactDOM 很重要。React 是用于创建组件和管理状态的核心库。ReactDOM 则负责将这些组件渲染到浏览器的 DOM 中。虽然 React 可以在其他环境中使用(例如用于移动开发的 React Native,它使用不同的渲染库),但 ReactDOM 是专为 Web 应用程序设计的。
关键的 ReactDOM 方法
让我们来探索一下 ReactDOM 包提供的一些最重要的方法:
ReactDOM.render()
ReactDOM.render()
方法是任何 React 应用程序的基础。它负责将一个 React 组件(或组件树)挂载到指定的 DOM 节点上。这个节点通常是页面中的一个空 HTML 元素。
语法:
ReactDOM.render(element, container[, callback])
element
:你想要渲染的 React 元素。这通常是你应用程序的顶层组件。container
:你想要挂载组件的 DOM 元素。这应该是你 HTML 中的一个有效 DOM 节点。callback
(可选):一个在组件渲染完成后将执行的函数。
示例:
假设你有一个名为 App
的简单 React 组件:
import React from 'react';
import ReactDOM from 'react-dom/client';
function App() {
return (
<div>
<h1>Hello, React!</h1>
<p>This is a simple React component.</p>
</div>
);
}
以及一个带有名为 "root" 的 ID 的元素的 HTML 文件:
<div id="root"></div>
要将 App
组件渲染到 "root" 元素中,你可以使用:
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
重要提示 (React 18 及更高版本): 在 React 18 及更高版本中,ReactDOM.render
已被视为旧版 API。推荐的方法是使用如上所示的 ReactDOM.createRoot
。这会启用 React 18 中引入的新的并发功能。
理解更新: ReactDOM.render()
也负责在组件数据变化时更新 DOM。React 使用虚拟 DOM 来高效地比较当前状态和期望状态,并且只更新真实 DOM 中必要的部分,从而最大限度地减少性能开销。
ReactDOM.hydrate()
当你渲染一个已经在服务器上渲染过的 React 应用程序时,会使用 ReactDOM.hydrate()
。这是提高应用程序初始加载性能和增强 SEO 的关键技术。
服务器端渲染 (SSR): 在 SSR 中,React 组件在服务器上被渲染成 HTML。然后这个 HTML 被发送到浏览器,浏览器可以立即显示初始内容。但是,浏览器仍然需要“水合”(hydrate) 应用程序——也就是附加事件监听器并使应用程序具有交互性。ReactDOM.hydrate()
会接管服务器渲染的 HTML,并将 React 事件处理器附加到上面,使应用程序功能完备。
语法:
ReactDOM.hydrate(element, container[, callback])
参数与 ReactDOM.render()
相同。
示例:
在服务器上,你会将你的 React 应用程序渲染成一个字符串:
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './App';
const html = ReactDOMServer.renderToString(<App />);
然后这个 HTML 会被发送到客户端。
在客户端,你会使用 ReactDOM.hydrate()
来附加 React 事件处理器:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.hydrate(<App />);
水合 (Hydration) 的好处:
- 提高初始加载速度: 用户可以立即看到内容,甚至在 JavaScript 代码完全加载之前。
- 增强 SEO: 搜索引擎可以抓取并索引完全渲染后的 HTML。
ReactDOM.unmountComponentAtNode()
ReactDOM.unmountComponentAtNode()
用于从 DOM 中移除一个已挂载的组件。当需要动态移除部分 UI 或在导航到其他页面前清理资源时,这个方法很有用。
语法:
ReactDOM.unmountComponentAtNode(container)
container
:组件挂载的 DOM 元素。
示例:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const rootElement = document.getElementById('root');
const root = ReactDOM.createRoot(rootElement);
root.render(<App />);
// 之后,要卸载该组件:
root.unmount();
调用 ReactDOM.unmountComponentAtNode(rootElement)
后,App
组件将从 DOM 中移除,并且所有与之相关的事件监听器和资源都将被清理。
使用场景:
- 从 UI 中移除一个模态框或对话框。
- 在导航到不同页面之前清理组件。
- 在不同组件之间动态切换。
ReactDOM.findDOMNode() (已废弃)
重要提示: ReactDOM.findDOMNode()
已被视为旧版 API,不推荐在现代 React 应用程序中使用。它以前用于访问已挂载组件的底层 DOM 节点。但是,不鼓励使用它,因为它破坏了 React 的抽象,并可能导致不可预测的行为,尤其是在引入函数组件和 Hooks 之后。
替代方法:
与其使用 ReactDOM.findDOMNode()
,不如考虑以下这些替代方法:
- Refs: 使用 React refs 来直接访问 DOM 节点。这是与 DOM 元素交互的推荐方法。
- 受控组件: 通过使用 React 管理其状态,使你的组件成为“受控”组件。这允许你在不直接访问 DOM 的情况下操控 UI。
- 事件处理器: 为你的组件附加事件处理器,并使用事件对象来访问目标 DOM 元素。
React 18 中的并发性与 ReactDOM
React 18 引入了并发性 (concurrency),这是一种新的机制,允许 React 中断、暂停、恢复或放弃渲染任务。这解锁了诸如过渡 (transitions) 和选择性水合 (selective hydration) 等强大功能,带来了更流畅、响应更快的用户体验。
对 ReactDOM 的影响: 采用 ReactDOM.createRoot
对于利用并发性的好处至关重要。此方法创建一个根,你的应用程序从该根进行渲染,使 React 能够更有效地管理渲染任务。
过渡 (Transitions): 过渡允许你将某些状态更新标记为非紧急,从而使 React 能够优先处理更重要的更新并保持响应性。例如,在路由之间导航时,你可以将路由转换标记为非紧急更新,以确保即使在数据获取期间 UI 也能保持响应。
选择性水合 (Selective Hydration): 通过选择性水合,React 可以按需水合单个组件,而不是一次性水合整个应用程序。这显著改善了大型应用程序的初始加载时间。
React ReactDOM 的全球化考量
在为全球用户开发 React 应用程序时,考虑国际化 (i18n) 和本地化 (l10n) 等因素非常重要。ReactDOM 本身不直接处理这些方面,但将其与 i18n 库和最佳实践集成至关重要。
- 国际化 (i18n): 设计和开发能够适应不同语言和地区而无需工程更改的应用程序的过程。
- 本地化 (l10n): 通过翻译文本、调整格式和处理文化差异,为特定语言或地区调整国际化应用程序的过程。
使用 i18n 库:
像 react-i18next
和 globalize
这样的库提供了管理翻译、日期和时间格式化以及其他与本地化相关的任务的工具。这些库通常与 React 和 ReactDOM 无缝集成。
使用 react-i18next 的示例:
import React from 'react';
import { useTranslation } from 'react-i18next';
function MyComponent() {
const { t } = useTranslation();
return (
<div>
<h1>{t('greeting')}</h1>
<p>{t('description')}</p>
</div>
);
}
在这个例子中,useTranslation
钩子提供了对翻译函数 t
的访问,该函数会根据给定的键检索相应的翻译。翻译内容本身通常存储在每种语言的单独文件中。
从右到左 (RTL) 布局:
某些语言,如阿拉伯语和希伯来语,是从右到左书写的。在为这些语言开发应用程序时,你需要确保你的 UI 支持 RTL 布局。这通常涉及调整文本方向、镜像组件布局以及处理双向文本。
使用 ReactDOM 的最佳实践
为了确保 React 应用程序高效且可维护,请在使用 ReactDOM 时遵循以下最佳实践:
- 在 React 18 及更高版本中使用
ReactDOM.createRoot
:这是渲染应用程序并利用并发性优势的推荐方式。 - 避免直接操作 DOM:让 React 管理 DOM。直接操作 DOM 可能导致不一致和性能问题。
- 谨慎使用 refs:仅在需要直接访问 DOM 节点以实现特定目的(例如聚焦输入元素)时才使用 refs。
- 优化渲染性能:使用诸如 memoization 和 shouldComponentUpdate 等技术来防止不必要的重新渲染。
- 考虑使用服务器端渲染以提高性能和 SEO。
- 使用 i18n 库进行国际化和本地化。
- 在不同浏览器和设备上彻底测试你的应用程序。
结论
ReactDOM 是 React 生态系统中必不可少的一部分,它提供了 React 组件与浏览器 DOM 之间的桥梁。通过理解像 ReactDOM.render()
、ReactDOM.hydrate()
和 ReactDOM.unmountComponentAtNode()
这样的关键方法,并采纳最佳实践,你可以构建高性能、可维护且全球可访问的 React 应用程序。随着 React 18 中并发性的引入,拥抱 ReactDOM.createRoot
对于解锁更高水平的性能和响应性至关重要。在为全球用户构建应用时,请记住考虑国际化和本地化的最佳实践,以创造真正具有包容性和可访问性的用户体验。